#!/usr/bin/python

from xml.dom import minidom
import urllib2
import gzip
import cStringIO
import sys
import re

API_KEY = ""
URL = "http://www.discogs.com/release/$REL_ID$?f=xml&api_key=$API_KEY$"

class Discogs(object):
    """
    The Discogs class allows you to supply a discogs "release ID", and obtain the 
    following attributes .

        Album artist  : artist
        Album title   : title
        Release year  : year
        Record label  : label 
        Cat number    : getCatNo
        Track list    : track_list

    Discogs requires you to obtain your own API key 
    (see http://www.discogs.com/users/api_key). 
    Please see their API wiki (http://www.discogs.com/help/api) for more information.
    Sample code :

    The following code obtains release information for Discogs release 40522,
    Blunted Dummies - House for All

    $ python
    >>> from discogs import Discogs
    >>> r = Discogs('40522')
    >>> print r.artist + '-' + r.title
    Blunted Dummies-House For All

    >>> for c, a, t in r.track_list:
        ...     print "%d : %s - %s" % (c, a, t)
        ... 

    1 : Blunted Dummies - House For All (Original Mix)
    2 : Blunted Dummies - House For All (House 4 All Robots Mix)
    3 : Blunted Dummies - House For All (Eddie Richard's Mix)
    4 : Blunted Dummies - House For All (J. Acquaviva's Mix)
    5 : Blunted Dummies - House For All (Ruby Fruit Jungle Mix)

    A wrapper script (py_tag.py) is also available, that implements the discogs class for 
    directory/file tagging.
 
    jesse @ housejunkie . ca        
    """

    def __init__(self, relId, build = 1):
        self.relId = relId
        self.url = URL.replace("$REL_ID$", relId, 1)
        self.url = self.url.replace('$API_KEY$', API_KEY,1)
        self.relxml = self.load_xml()
        self.artist = ''
        self.title = ''
        self.year = ''
        self.label = ''
        self.cat_num = ''
        self.genre = ''
        self.track_list = []

        # instanciating Discogs automatically populates all
        # records from the releaseId
        if build:
            self.artist = self.parse_artists()
            self.title = self.parse_title()
            self.year = self.parse_year()
            self.label = self.parse_label()
            self.cat_num = self.parse_cat_num()
            self.track_list = self.parse_track_list()
            self.genre = self.parse_genre()

    def load_xml(self):
        """
        fetches a copy of the response XML provided by the discogs
        api. See here http://www.discogs.com/help/api for docs.
        """
        request = urllib2.Request(self.url)
        request.add_header('Accept-Encoding', 'gzip')

        try:
            response = urllib2.urlopen(request)
            data = response.read()
        except urllib2.URLError, urllib2.HTTPError:
            print "[ERROR] unable to connect to Discogs : %s" %self.url
            sys.exit()

        # discogs no longer returns _all_ responses as gzipped encoding
        # adding an additional check before passing off to parser
        if response.headers.getheader('Content-Encoding') == 'gzip':
            relxml = minidom.parseString(gzip.GzipFile(fileobj = \
                        cStringIO.StringIO(data)).read())
        else:
            relxml = minidom.parseString(cStringIO.StringIO(data).read())
             
        return relxml
    
    def parse_label(self):
        label = self.relxml.getElementsByTagName('label')[0]
        return self.clean_name(label.attributes["name"].value)

    def parse_cat_num(self):
        catno = self.relxml.getElementsByTagName('label')[0]
        return catno.attributes["catno"].value

    def parse_title(self, node = None):
        if node == None:
            node = self.relxml
        return node.getElementsByTagName('title')[0].firstChild.data

    def parse_year(self, format = 1):
        """
        Parse year of release from xml feed. Currently
        Exits if data is not present. May want to set a
        default value and remove the sys.exit(), if the
        year isn't a requirement for your needs.
        """ 
        try:
            year = self.relxml.getElementsByTagName('released')[0].firstChild.data
        except IndexError:
            print "[ERROR] unable to obain release year for : %s" %self.relId
            sys.exit()
        if format:
            return self.clean_year(year)
        else:
            return year

    def parse_artists(self, node = None):
        """
        retrieve both the album/release artists
        or the individual artists of each track
        """
        if node == None:
            node = self.relxml
        count = 1
        try:
            artists = node.getElementsByTagName('artists')[0]
        except IndexError:
            return self.artist
        for nme in artists.getElementsByTagName('name'):
            if count == 1:
                name = nme.firstChild.data
            else:
                name = name + " & " + nme.firstChild.data
            count += 1
        return self.clean_name(name)

    def parse_track_list(self):
        """
        returns a list (tlist), in the following format
        [ [track id, "artist", "track title"] ] 
        """
        tlist = []
        count = 1
        trackList = self.relxml.getElementsByTagName('tracklist')[0]
        for tracks in trackList.getElementsByTagName('track'):
            tlist.extend([[ count, self.parse_artists(tracks), self.parse_title(tracks)]]) 
            count += 1
        return tlist

    def parse_genre(self):
        """
        Obtains the first <style></style> within the <styles> tag
        """        
        try:
            styles = self.relxml.getElementsByTagName('styles')[0]
            style = styles.getElementsByTagName('style')[0].firstChild.data
        except IndexError:
            style = self.relxml.getElementsByTagName('genre')[0].firstChild.data
 
        return style

    def clean_name(self, name):
        """
        Cleans up the formatting of artist/label names.
        Discogs orders duplicate names by appending a counter to each dupe
        eg : http://www.discogs.com/search?type=artists&q=goldie&btn=Search
        Goldie
        Goldie (1)
        Goldie (16)
        """
        r = re.compile('\s\(\d+\)')
        return r.sub('', name)

    def clean_year(self, year):
        """
        Returns the release year in the format : YYYY
        """
        save = re.compile('(\d\d\d\d)')
        return save.match(year).group(1)

    def disc_debug(self):
        """
        Debug method to dump all attributes assigned to current Discogs object
        """
        div = "_ _______________________________________________ _ _\n"
        r = div
        r += " Name : %s - %s\n" % (self.artist, self.title)
        r += "Label : %s\n" % (self.label)
        r += "Genre : %s\n" % (self.genre)
        r += "Catno : %s\n" % (self.cat_num)
        r += " Year : %s\n" % (self.year)
        r += "  URL : http:/www.discogs.com/release/%s\n" % (self.relId)
        r += div
        for cnt, art, trk in self.track_list:
            r += "%.2d %s - %s\n" % (cnt, art, trk)
        r += div
        r += ":: generated by disc_debug > questions > jesse@housejunkie.ca\n"
        return r
